package OtherMethod;

import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import ImgCombine.ImageCombine;
import XmlLoader.FGObjProcess;
import XmlLoader.FGObjectStructure;
import XmlLoader.FGObjectTrajectoryStructure;
import XmlLoader.Position;

public class DataViewer {
	
	protected int totalTraj = 0;
	protected int totalPoint = 0;
	protected double timeCoverageMorePoint = 0.0;
	protected double coverageLowCorrelationPoint = 0.0;
	protected double farDist = 100;
	protected PointTimeList ptl = new PointTimeList();
	
	protected void _001_writeMatLabArray(String filePath, List<Integer> list_x, List<Integer> list_y, int numPerRow, String drawType, boolean isXReverse, boolean isYReverse) {
		File file = new File(filePath);
		BufferedWriter bufWriter = null;
		int index_x = 0, index_y = 0, indexWriteTime = 0;
		try {
			bufWriter = new BufferedWriter(
					new OutputStreamWriter(new FileOutputStream(file,false),"utf8"));
			//write initial setting
			bufWriter.write("clc;\n");
			bufWriter.write("clear;\n");
			//write all point data of X
			indexWriteTime = 0;
			bufWriter.write("x=[");
			index_x = 0;
			while(index_x < list_x.size()) {
				bufWriter.write(Integer.toString(list_x.get(index_x)) + " ");
				indexWriteTime = indexWriteTime + 1;
				if(indexWriteTime % numPerRow == 0) {
					bufWriter.write("...\n");
				}
				index_x = index_x + 1;
			}
			bufWriter.write("];\n");
			//write all point data of Y
			indexWriteTime = 0;
			bufWriter.write("y=[");
			index_y = 0;
			while(index_y < list_y.size()) {
				bufWriter.write(Integer.toString(list_y.get(index_y)) + " ");
				indexWriteTime = indexWriteTime + 1;
				if(indexWriteTime % numPerRow == 0) {
					bufWriter.write("...\n");
				}
				index_y = index_y + 1;
			}
			bufWriter.write("];\n");
			bufWriter.write(drawType + "(x,y,'r');");
			if(isXReverse) {
				bufWriter.write("set(gca, 'XDir', 'reverse');");
			}
			if(isYReverse) {
				bufWriter.write("set(gca, 'YDir', 'reverse');");
			}
			bufWriter.close();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	protected double _002_coutGroupAverage(int[] group) {
		double sum = 0.0;
		int index = 0;
		while(index < group.length) {
			sum = sum + group[index];
			index = index + 1;
		}
		return sum / group.length;
	}
	
	protected double _003_countTwoRectangleMinDist(String filePathPicture, int firstTrajId, int firstPointId, Position firstPos,
			int secondTrajId, int secondPointId, Position secondPos) {
		double dist = 0.0;
		ImageCombine ic = new ImageCombine("", filePathPicture, "");
		boolean isLengthCover = false, isWidthCover = false;
		int dist1 = 0, dist2 = 0;
		//get POI file path of first and second point
		String filePathFirstPic = ic._003_getObjFileName(false, firstTrajId, firstPointId);
		String filePathSecondPic = ic._003_getObjFileName(false, secondTrajId, secondPointId);
		//get image file path of first and second point to know the size of image
		BufferedImage imgFirst = ic._001_loadImgBuffer(filePathFirstPic);
		BufferedImage imgSecond = ic._001_loadImgBuffer(filePathFirstPic);
		//create rectangle obj
		Rectangle firstRect = new Rectangle(firstPos, imgFirst.getWidth(), imgFirst.getHeight());
		Rectangle secondRect = new Rectangle(secondPos, imgSecond.getWidth(), imgSecond.getHeight());
		//count distance
		if((firstPos.x >= secondPos.x && firstPos.x <= secondPos.x + imgSecond.getWidth()) || 
		   (firstPos.x + imgFirst.getWidth() >= secondPos.x && firstPos.x + imgFirst.getWidth() <= secondPos.x + imgSecond.getWidth())) {
			isLengthCover = true;
		}
		if((firstPos.y >= secondPos.y && firstPos.y <= secondPos.y + imgSecond.getHeight()) || 
				   (firstPos.y + imgFirst.getHeight() >= secondPos.y && firstPos.y + imgFirst.getHeight() <= secondPos.y + imgSecond.getHeight())) {
			isWidthCover = true;
		}
		if(isLengthCover&isWidthCover == true) {
			dist = 0.0;
		}
		else {
			if(isLengthCover) {
				dist1 = Math.abs(firstPos.y - (secondPos.y + imgSecond.getHeight()));
				dist2 = Math.abs(firstPos.y + imgFirst.getHeight() - secondPos.y);
				if(dist1 < dist2) {
					dist = dist1;
				}
				else {
					dist = dist2;
				}
			}
			else if (isWidthCover) {
				dist1 = Math.abs(firstPos.x - (secondPos.x + imgSecond.getWidth()));
				dist2 = Math.abs(firstPos.x + imgFirst.getWidth() - secondPos.x);
				if(dist1 < dist2) {
					dist = dist1;
				}
				else {
					dist = dist2;
				}
			}
			else {
				if(firstPos.x < secondPos.x) {
					if(firstPos.y > secondPos.y) {  //firstPos is in left-up of the second point
						Position pos1 = new Position();
						pos1.x = firstPos.x + imgFirst.getWidth();
						pos1.y = firstPos.y + imgFirst.getHeight();
						dist = secondPos.ACT001_countDist(pos1);
					}
					else {  //firstPos is in left-down of the second point
						Position pos1 = new Position();
						pos1.x = firstPos.x + imgFirst.getWidth();
						pos1.y = firstPos.y;
						Position pos2 = new Position();
						pos2.x = secondPos.x;
						pos2.y = secondPos.y + imgSecond.getHeight();
						dist = pos1.ACT001_countDist(pos2);
					}
				}
				else {
					if(firstPos.y > secondPos.y) {  //firstPos is in right-up of the second point
						Position pos1 = new Position();
						pos1.x = firstPos.x;
						pos1.y = firstPos.y + imgFirst.getHeight();
						Position pos2 = new Position();
						pos2.x = secondPos.x + imgSecond.getWidth();
						pos2.y = secondPos.y;
						dist = pos1.ACT001_countDist(pos2);
					}
					else {  //firstPos is in right-down of the second point
						Position pos2 = new Position();
						pos2.x = secondPos.x + imgFirst.getWidth();
						pos2.y = secondPos.y + imgSecond.getHeight();
						dist = firstPos.ACT001_countDist(pos2);
					}
				}
			}
		}
		return dist;
	}
	
	public void ACT001_writeToMatLabFormShowPoint(List<FGObjectTrajectoryStructure> list, 
			String filePath, int numPerRow, int numForGroup) {
		int indexTraj = 0, indexPos = 0, indexWriteTime = 0, getNum = 0;
		File file = new File(filePath);
		BufferedWriter bufWriter = null;
		int indexGroup = 0;
		int[] groupDataTemp = new int[numForGroup];
		try {
			bufWriter = new BufferedWriter(
					new OutputStreamWriter(new FileOutputStream(file,false),"utf8"));
			//write initial setting
			bufWriter.write("clc;\n");
			bufWriter.write("clear;\n");
			//write all point data of X
			indexWriteTime = 0;
			bufWriter.write("x=[");
			indexTraj = 0;
			indexGroup = 0;
			this.totalTraj = list.size();
			while(indexTraj < list.size()) {
				indexPos = 0;
				while(indexPos < list.get(indexTraj).GET002_nNumberOfPoint()) {
					getNum = list.get(indexTraj).GET003_elementIn_list_fGObject(indexPos).GET001_centerReal().x;
					if(indexGroup < numForGroup) {  //store data to group for grouping
						groupDataTemp[indexGroup] = getNum;
						indexGroup = indexGroup + 1;
					}
					else {
					    bufWriter.write(Integer.toString((int)this._002_coutGroupAverage(groupDataTemp)) + " ");
					    indexWriteTime = indexWriteTime + 1;
					    if(indexWriteTime % numPerRow == 0) {
							bufWriter.write("...\n");
						}
					    indexGroup = 0;
					}
					indexPos = indexPos + 1;
				}
				if(indexGroup > 0){  //write the final data
					bufWriter.write(Integer.toString((int)this._002_coutGroupAverage(groupDataTemp)) + " ");
				}
				this.totalPoint = this.totalPoint + list.get(indexTraj).GET002_nNumberOfPoint();
				indexTraj = indexTraj + 1;
			}
			bufWriter.write("];\n");
			//write all point data of Y
			indexWriteTime = 0;
			bufWriter.write("y=[");
			indexTraj = 0;
			indexGroup = 0;
			while(indexTraj < list.size()) {
				indexPos = 0;
				while(indexPos < list.get(indexTraj).GET002_nNumberOfPoint()) {
					getNum = list.get(indexTraj).GET003_elementIn_list_fGObject(indexPos).GET001_centerReal().y;
					if(indexGroup < numForGroup) {  //store data to group for grouping
						groupDataTemp[indexGroup] = getNum;
						indexGroup = indexGroup + 1;
					}
					else {
					    bufWriter.write(Integer.toString((int)this._002_coutGroupAverage(groupDataTemp)) + " ");
					    indexWriteTime = indexWriteTime + 1;
					    if(indexWriteTime % numPerRow == 0) {
							bufWriter.write("...\n");
						}
					    indexGroup = 0;
					}
					indexPos = indexPos + 1;
				}
				if(indexGroup > 0){  //write the final data
					bufWriter.write(Integer.toString((int)this._002_coutGroupAverage(groupDataTemp)) + " ");
				}
				indexTraj = indexTraj + 1;
			}
			bufWriter.write("];\n");
			bufWriter.write("scatter(x,y,'.');\n");
			bufWriter.write("set(gca, 'YDir', 'reverse');");
			bufWriter.close();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void ACT002_writeToMatLabFormShowNNDistribution(List<FGObjectTrajectoryStructure> list, 
			String filePath, String filePathPic) {
		/* store all trajectory point into structure - PointTimeList */
		int indexTraj = 0, indexPos = 0;
		//read each trajectory data
		indexTraj = 0;
		while(indexTraj < list.size()) {
			//read each point data for one trajectory data
			indexPos = 0;
			while(indexPos < list.get(indexTraj).GET002_nNumberOfPoint()) {
				FGObjectStructure getPoint = list.get(indexTraj).GET003_elementIn_list_fGObject(indexPos);
				Position getPos = getPoint.GET001_centerReal();
				int getTime = getPoint.GET002_tOrigin();
				this.ptl.ACT001_add(getTime, getPos, indexTraj, indexPos);
				indexPos = indexPos + 1;
			}
			indexTraj = indexTraj + 1;
		}
		/* find each point of NN in specific time and store to table */
		StatisticTable st = new StatisticTable();
		int indexTime = 0, indexTargetObj = 0, indexCheckObj = 0;
		double curMaxDist = 0;
		HashMap<Integer, List<PosAndID>> hash = this.ptl.GET001_hashTime_Pos();
		Integer[] timeKeySet = hash.keySet().toArray(new Integer[0]);
		while(indexTime < hash.size()) {
			List<PosAndID> listPos = hash.get(timeKeySet[indexTime]);
			indexTargetObj = 0;
			if(listPos.size() > 1) {  //check whether there are more than one point in current time
				this.timeCoverageMorePoint = this.timeCoverageMorePoint + 1;
			}
			else {
				coverageLowCorrelationPoint = coverageLowCorrelationPoint + 1;
			}
			while(indexTargetObj < listPos.size()) {
				Position targetPos = listPos.get(indexTargetObj).pos;
				indexCheckObj = 0;
				curMaxDist = 0;
				while(indexCheckObj < listPos.size()) {
					if(indexCheckObj != indexTargetObj) {
						double countDist = this._003_countTwoRectangleMinDist(filePathPic, listPos.get(indexTargetObj).trajID, 
								listPos.get(indexTargetObj).pointID, listPos.get(indexTargetObj).pos, 
								listPos.get(indexCheckObj).trajID, listPos.get(indexCheckObj).pointID, 
								listPos.get(indexCheckObj).pos);
						if(curMaxDist == 0) {
							curMaxDist = countDist;
						}
						else if(countDist < curMaxDist) {
							curMaxDist = countDist;
						}
					}
					indexCheckObj = indexCheckObj + 1;
				}
				if(listPos.size() > 1) {
					if(curMaxDist >= this.farDist) {
						coverageLowCorrelationPoint = coverageLowCorrelationPoint + 1;
					}
				    st.ACT001_add("", curMaxDist);
				}
				indexTargetObj = indexTargetObj + 1;
			}
			indexTime = indexTime + 1;
		}
		this.timeCoverageMorePoint = this.timeCoverageMorePoint / hash.size();
		this.coverageLowCorrelationPoint = this.coverageLowCorrelationPoint / this.totalPoint;
		
		/* According to table, write to matlab form plotting */
		List<Element> list_st = st.GET001_list();
		int indexST = 0, indexCurDist = 0, indexCurDistTime = 0;
		List<Integer> list_dist = new ArrayList<Integer>();
		List<Integer> list_time = new ArrayList<Integer>();
		boolean isFirst = true;
		Element curEle = null;
		while(indexST < list_st.size()) {
			curEle = list_st.get(indexST);
			if(isFirst) {  //first time to read data
				indexCurDist = (int)curEle.content;
				indexCurDistTime = 1;
				isFirst = false;
			}
			else if(indexCurDist == (int)curEle.content) {  //if value is the same as original, add 1
				indexCurDistTime = indexCurDistTime + 1;
			}
			else {  //if value is not the same, do record and change to next distant
				list_dist.add(indexCurDist);
				list_time.add(indexCurDistTime);
				
				indexCurDist = (int)curEle.content;
				indexCurDistTime = 1;
			}
			indexST = indexST + 1;
		}
		this._001_writeMatLabArray(filePath, list_dist, list_time, 15, "plot", false, false);
	}
	
	public void ACT003_showReport() {
		System.out.println("Traj total number = " + this.totalTraj + "\n");
		System.out.println("Point total number = " + this.totalPoint + "\n");
		System.out.println("More than one point coverage = " + this.timeCoverageMorePoint + "\n");
		System.out.println("Low correlation point % = " + this.coverageLowCorrelationPoint);
	}
	
	public void ACT004_writeToMatLabFormShowDataToTimeDistribution(String filePath, int numPerRow) {
		int index_ptl = 0;
		StatisticAcmTable sat = new StatisticAcmTable();
		Integer[] keySet = this.ptl.GET001_hashTime_Pos().keySet().toArray(new Integer[0]);
		while(index_ptl < this.ptl.GET001_hashTime_Pos().size()) {
			sat.ACT001_add(Integer.toString(this.ptl.GET001_hashTime_Pos().get(keySet[index_ptl]).size()), 0);
			index_ptl = index_ptl + 1;
		}
		
		/* According to table, write to matlab form plotting */
		List<Integer> list_objNum = new ArrayList<Integer>();
		List<Integer> list_appearTime = new ArrayList<Integer>();
		List<Element> list_sat = sat.GET001_list();
		int index_sat = 0;
		while(index_sat < list_sat.size()) {
			list_objNum.add(Integer.parseInt(list_sat.get(index_sat).title));
			list_appearTime.add((int)list_sat.get(index_sat).content);
			index_sat = index_sat + 1;
		}
		this._001_writeMatLabArray(filePath, list_objNum, list_appearTime, numPerRow, "plot", false, false);
	}
	
	public void ACT005_drawAllTrajLine(List<FGObjectTrajectoryStructure> list, String filePath) {
		int indexTraj = 0, indexPos = 0;
		File file = new File(filePath);
		BufferedWriter bufWriter = null;
		try {
			bufWriter = new BufferedWriter(
					new OutputStreamWriter(new FileOutputStream(file,false),"utf8"));
			//write initial setting
			bufWriter.write("clc;\n");
			bufWriter.write("clear;\n");
			//write each trajectory
			indexTraj = 0;
			this.totalTraj = list.size();
			while(indexTraj < list.size()) {
				if(list.get(indexTraj).GET002_nNumberOfPoint() > 5 && Math.random()*10 + 1 >= 4) { //sample some trajectory to draw
					String xPart = "x" + indexTraj + "=[";
					String yPart = "y" + indexTraj + "=[";
					indexPos = 0;
					while(indexPos < list.get(indexTraj).GET002_nNumberOfPoint()) {
						//add x axis
						xPart = xPart + list.get(indexTraj).GET003_elementIn_list_fGObject(indexPos).GET001_centerReal().x;
						//add y axis
						yPart = yPart + list.get(indexTraj).GET003_elementIn_list_fGObject(indexPos).GET001_centerReal().y;
						//check finish
						if(indexPos < list.get(indexTraj).GET002_nNumberOfPoint() - 1) {
							xPart = xPart + ",";
							yPart = yPart + ",";
						}
						else
						{
							xPart = xPart + "];";
							yPart = yPart + "];";
						}
						indexPos = indexPos + 1;
					}
					//write trajectory storage command
					bufWriter.write(xPart + "\n");
					bufWriter.write(yPart + "\n");
					//write line command
					bufWriter.write("line(" + "x" + indexTraj + "," + "y" + indexTraj + ");\n");
				}
				indexTraj = indexTraj + 1;
			}
			bufWriter.write("set(gca, 'YDir', 'reverse');\n");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		FGObjProcess fgObj = new FGObjProcess(args[1]);
		List<String> list_objIndex = fgObj.ACT004_getStringList(args[0]);
    	List<FGObjectTrajectoryStructure> list = fgObj.ACT001_getListOfObj(list_objIndex);
    	
    	DataViewer dv = new DataViewer();
    	dv.ACT001_writeToMatLabFormShowPoint(list, "ppshow.m", 15, 10);
    	//dv.ACT002_writeToMatLabFormShowNNDistribution(list, "nnshow.m", args[2]);
    	//dv.ACT004_writeToMatLabFormShowDataToTimeDistribution("dtshow.m", 15);
    	dv.ACT005_drawAllTrajLine(list, "lineshow.m");
    	dv.ACT003_showReport();
	}
}
